Portable model documents ========================= A parsed RISE model is a large object full of derived structure: expanded equations, auxiliary variables the parser introduced, symbolic derivatives, solver scaffolding. Saving it with ``save`` produces a binary file that cannot be read, cannot be reviewed, and cannot be relied on across versions. A **portable document** is the same model written as readable JSON. It is versioned, so a reader knows what it is looking at. It is complete enough to rebuild the model. And it is comparable, so two documents can be diffed the way source is diffed, in model terms rather than as text lines. .. contents:: :local: :depth: 2 Writing a model out -------------------- .. code-block:: matlab m = dsge_model('fs2000'); rise.to_portable(m, 'fs2000.json'); % write a file doc = rise.to_portable(m); % or keep the document Options: ``Force`` (default ``false``) Write even when part of the model cannot be carried in readable form. The document then describes less than the model does, so the default is to refuse rather than to produce a document that quietly omits something. ``IncludeValues`` (default ``true``) Carry parameter values alongside the structure. The document records a format version, and that version is the contract: .. code-block:: matlab doc.format % rise-portable/1.0.0 Reading one back ----------------- .. code-block:: matlab m2 = rise.from_portable('fs2000.json'); m2 = rise.from_portable(doc); Options: ``KeepSource`` Keep the reconstructed RISE model file at a path you name rather than in a temporary one. Useful when you want to see exactly what was parsed. ``ModelOptions`` A cell array forwarded to the model constructor. A document written in a format this build does not read is refused by name: .. code-block:: none RISE:portable:unsupportedFormat This document is written in format rise-portable/99.0.0. This build reads rise-portable/1.0.0. Rewrite it with the version of RISE that produced it, or read it with a build that supports it. Comparing two models --------------------- .. code-block:: matlab rise.portable_diff('baseline.json', 'revision.json') % prints report = rise.portable_diff(mOld, mNew); % returns Either side may be a file, a document or a model. The report has a field per section -- ``endogenous``, ``exogenous``, ``parameters``, ``observables``, ``markov_chains``, ``equations``, ``values`` -- and an ``identical`` flag. The comparison is in model terms. Reordering a declaration block, renaming a file or reformatting a comment produces no difference, which is what makes this more useful than diffing two model files. A changed value or a changed equation does: .. code-block:: none values changed (1): delta 0.02 -> 0.025 equations changed (1): [1] before: efficiency{t}=rho*efficiency{t-1}+(std_EfficiencyInnovation*EfficiencyInnovation{t}); after : efficiency{t}=rho*efficiency{t-1}+0.1*efficiency{t-2}+(std_EfficiencyInnovation*EfficiencyInnovation{t}); What the round trip guarantees ------------------------------- Writing a model out, reading it back, and writing it out again must produce the same document. That is the property the implementation is built around and the one the tests check: .. code-block:: matlab doc = rise.to_portable(m); m2 = rise.from_portable(doc); report = rise.portable_diff(doc, rise.to_portable(m2)); report.identical % true Two parser details make this less obvious than it looks, and both are handled rather than worked around. Definitions are not a block of their own. They are ``#``-prefixed statements inside ``@model``, so a document that emitted them separately would declare them twice on the way back in. The dynamic equation list includes equations the parser generated for auxiliary variables, such as the extra lag of a variable that appears at ``{-2}``. Carrying those would declare the auxiliary twice, so equations that mention one are dropped: the parser recreates them on the way back. What it is for --------------- * **Review.** A model change becomes a readable diff in a pull request instead of an opaque binary. * **Archival.** A document outlives the version of RISE that wrote it, because the format is versioned and the reader says so when it cannot read one. * **Comparison.** Two vintages of the same model, or a model and its Dynare conversion, compared in model terms. Worked example: ``rise-modern-tutorials/WorkingWithAModel/portable_model``. .. seealso:: :doc:`Understanding a rise_model object`, :doc:`Parameterization outside model file`